package com.learning.spring.ioc.webapplicationcontext.initializer;

import com.learning.spring.ioc.webapplicationcontext.config.SpringContextConfig;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;


/**
 * ClassName: WebInitializer
 * Description: IoC 容器 - 应用上下文（ApplicationContext）
 * <p>
 * 1. Servlet 3.0 支持使用 ServletContainerInitializer 代替 web.xml 配置，用于Servlet容器的启动
 * 2. Spring 的 SpringServletContainerInitializer 类实现了 ServletContainerInitializer 接口，并且标注 WebApplicationInitializer 用于容器启动时具体处理业务
 * 3. 应用在开发时的具体实现方式，可以有：
 * 3.1 实现 WebApplicationInitializer 接口，重写 onStartup 方法
 * 3.2 Spring 有一个默认的 WebApplicationInitializer 接口实现类 AbstractContextLoaderInitializer，继承该类，重写其方法
 * <p>
 * Date: 2020/8/17 15:27 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class WebInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // 注册上下文与配置
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringContextConfig.class);
        ctx.setServletContext(servletContext);

        // 添加 Spring Listener
        servletContext.addListener(new ContextLoaderListener(ctx));

        // 添加 CharacterEncodingFilter
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("utf-8");
        FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter", characterEncodingFilter);
        registration.setAsyncSupported(isAsyncSupported());
        registration.addMappingForUrlPatterns(getDispatcherTypes(), false, "/*");

    }

    private boolean isAsyncSupported() {
        return true;
    }

    private EnumSet<DispatcherType> getDispatcherTypes() {
        return isAsyncSupported() ?
                EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ASYNC) :
                EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE);
    }
}